package com.muy.redis.view.component;

import com.intellij.icons.AllIcons;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.ActionPlaces;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.project.Project;
import com.intellij.ui.components.JBLabel;
import com.muy.redis.common.textfield.SearchKeywordFunUpdateAction;
import com.muy.redis.common.tree.AbstractMTTreePanel;
import com.muy.redis.common.tree.actions.MrRedisAddKeyAction;
import com.muy.redis.common.tree.actions.MrRedisDeleteKeyAction;
import com.muy.redis.common.tree.actions.TreeCollapseAction;
import com.muy.redis.common.tree.actions.TreeExpandAction;
import com.muy.redis.utils.*;
import com.muy.redis.view.window.redis.bean.MrRedisConnectionParam;
import com.muy.redis.view.window.redis.bean.MrRedisDb;
import com.muy.redis.view.window.redis.enums.RedisValueTypeEnum;
import com.muy.redis.view.window.redis.tree.MTTreeCellMrRedisEditorShowDb;
import com.muy.redis.view.window.redis.tree.MTTreeCellMrRedisKey;
import lombok.SneakyThrows;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.resps.ScanResult;

import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import static redis.clients.jedis.params.ScanParams.SCAN_POINTER_START;

/**
 * @Author jiyanghuang
 * @Date 2023/9/15 23:11
 */
public class MrRedisEditorJpanelLeft extends AbstractMTTreePanel {

    private Project project;
    private JBLabel pageSizeLabel;
    private JBLabel pageLabel;

    private int pageSize = 5;

    private List<String> allKeys = new ArrayList<>();
    private List<String> currentPageKeys = new ArrayList<>();
    private MrRedisConnectionParam mrRedisConnectionParam;
    private MrRedisDb mrRedisDb;
    private JButton prevPageButton;
    private JButton nextPageButton;
    private SearchKeywordFunUpdateAction searchKeywordFunUpdateAction;
    private long total = 0L;
    private MrRedisPagingPanel mrRedisPagingPanel;


    public MrRedisEditorJpanelLeft(Project project, MrRedisConnectionParam mrRedisConnectionParam, MrRedisDb mrRedisDb) {
        super(project, false);
        pageSize = mrRedisPagingPanel.getPageSize();
        this.project = project;
        this.mrRedisDb = mrRedisDb;
        this.mrRedisConnectionParam = mrRedisConnectionParam;
        RedisPoolManager redisPoolManager = MrRedisConnectionUtils.findRedisPoolManager(mrRedisConnectionParam);
        allKeys = redisPoolManager.scanKeys(SCAN_POINTER_START, "*", pageSize, mrRedisDb.getIndex());
        if (null == allKeys) {
            throw new RuntimeException("exception occurred");
        }
        searchKeywordFunUpdateAction.updateSearchFun((value) -> {
            renderKeyTree();
        });
        renderKeyTree();
    }

    @Override
    protected void installActions() {
        DefaultActionGroup actionGroup = new DefaultActionGroup("MTTreeGroup", false);
        if (null != ApplicationManager.getApplication()) {
            searchKeywordFunUpdateAction = new SearchKeywordFunUpdateAction(this);
            actionGroup.add(searchKeywordFunUpdateAction);
//            actionGroup.add(new ReloadRedisOneDbAction(this));
            actionGroup.add(new MrRedisAddKeyAction(this));
            actionGroup.add(new MrRedisDeleteKeyAction(this));
            actionGroup.addSeparator();
            actionGroup.add(new TreeExpandAction(tree));
            actionGroup.add(new TreeCollapseAction(tree));
            addActions(actionGroup);
        }

        GuiUtils.installActionGroupInToolBar(actionGroup, toolBarPanel, ActionManager.getInstance(), ActionPlaces.TOOLBAR, true);
    }

    /**
     * 渲染keyTree
     */
    @SneakyThrows
    public void renderKeyTree() {
        String keyFilter = searchKeywordFunUpdateAction.searchTextValue();
        if(StringUtils.isBlank(keyFilter)){
            keyFilter = "*";
        }
        String temp = keyFilter;
//        keyDisplayLoadingDecorator.startLoading(false);
        ReadAction.nonBlocking(() -> {
            try {
                RedisPoolManager redisPoolManager = MrRedisConnectionUtils.findRedisPoolManager(mrRedisConnectionParam);
                Long dbSize = redisPoolManager.dbSize(mrRedisDb.getIndex());
                if (dbSize == null) {
                    return null;
                }
                mrRedisDb.setKeyCount(dbSize);
                total = dbSize;
                // 添加DB node
                MTTreeCellMrRedisEditorShowDb showDb = new MTTreeCellMrRedisEditorShowDb(project, mrRedisDb);
                DefaultMutableTreeNode redisDbTreeNode = new DefaultMutableTreeNode(showDb);
                rootTreeNode.removeAllChildren();
                rootTreeNode.add(redisDbTreeNode);

                // redis 查询前pageSize个key
                int start = mrRedisPagingPanel.nextStart();
                allKeys = redisPoolManager.scanKeys(String.valueOf(start), temp, pageSize, mrRedisDb.getIndex());

                // exception occurred
                if (allKeys == null) {
                    return null;
                }

                if (CollectionUtils.isNotEmpty(allKeys)) {
//                    allKeys = allKeys.stream().sorted().collect(Collectors.toList());
//
//                    int size = allKeys.size();
//                    int start = (pageIndex - 1) * pageSize;
//                    int end = Math.min(start + pageSize, size);
                    currentPageKeys = allKeys;
                    if (!CollectionUtils.isEmpty(currentPageKeys)) {
                        for (String key : currentPageKeys) {
                            try (Jedis jedis = redisPoolManager.getJedis(mrRedisDb.getIndex())) {
                                if (jedis == null) {
                                    continue;
                                }
                                String type = jedis.type(key);
                                RedisValueTypeEnum redisValueTypeEnum = RedisValueTypeEnum.typeEnum(type);
                                MTTreeCellMrRedisKey redisKey = new MTTreeCellMrRedisKey(project, mrRedisDb, mrRedisConnectionParam, key, redisValueTypeEnum);
                                DefaultMutableTreeNode redisKeyTreeNode = new DefaultMutableTreeNode(redisKey);
                                redisDbTreeNode.add(redisKeyTreeNode);
                            }
                        }
                    }
                }

                JTreeUtils.reload(jTree(), rootTreeNode);
                JTreeUtils.expandOrCollapAll(jTree(), new TreePath(jTree().getModel().getRoot()), true);
                mrRedisPagingPanel.updateTotal(total);
                mrRedisPagingPanel.updateCurrentPageCount(currentPageKeys.size());
                mrRedisPagingPanel.updatePageLabel();
//                updatePageLabel();
            } finally {
//                keyDisplayLoadingDecorator.stopLoading();
            }
            return null;
        }).submit(ThreadPoolManager.getExecutor());

    }

    /**
     * @return
     */
    private long getPageCount() {
//        int total = 0;
//        if (null != allKeys) {
//            total = allKeys.size();
//        }
        long result = total / pageSize;
        long mod = total % pageSize;
        return mod > 0 ? result + 1 : result;
    }

    public void resetPageIndex(){
        mrRedisPagingPanel.resetPageIndex();
    }

    @Override
    public JPanel south() {
//        return createPagingPanel(null);
        mrRedisPagingPanel = new MrRedisPagingPanel((s) -> {
            renderKeyTree();
        });
        return mrRedisPagingPanel;
    }

    public MrRedisConnectionParam getMrRedisConnectionParam() {
        return mrRedisConnectionParam;
    }

    public MrRedisDb getMrRedisDb() {
        return mrRedisDb;
    }

    public Project getProject() {
        return project;
    }
}
